# coding=utf-8
# author='kungege21'
# date=2023/8/7 14:26
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
from starlette import status

app06 = APIRouter()

"""
OAuth2.0的授权模式
授权码授权模式；
隐式授权模式；
密码授权模式；
客户端凭证授权模式；
"""
"""
OAuth2 密码模式和 FastAPI 的 OAuth2PasswordBearer"""

"""
OAuth2PasswordBearer 是接收URL作为参数的一个类：客户端会向该URL发送username和password参数，然后得到一个Token值。
OAuth2PasswordBearer 并不会创建相应的URL路径，只是指明客户端用来请求Token的URL地址
当请求到来的时候，FastAPI会检查请求的Authorization头信息，如果没有找到Authorization头信息，或者头信息的内容不是Bearer token，它会返回401状态码（UNAUTHORIZED）
"""

oauth2 = OAuth2PasswordBearer(tokenUrl='/chapter06/token')  # 请求token的地址 http://127.0.0.1:8000/chapter06/token


@app06.get('/oauth2_password_bearer')
async def oauth2_password_bearer(token: str = Depends(oauth2)):
    return {'token': token}


"""基于 Password 和 Bearer token 的 OAuth2认证"""

# 模拟数据库用户数据
fake_users_db = {
    'john snow': {
        'username': 'john snow',
        'fullname': 'John Snow',
        'email': 'johnsnow@example.com',
        'hashed_password': 'fakehashedsecret',
        'disabled': False
    },
    'alice': {
        'username': 'alice',
        'fullname': 'Alice Wonderson',
        'email': 'alice@example.com',
        'hashed_password': 'fakehashedsecret2',
        'disabled': True
    }
}


# 模拟password加密算法
def fake_hash_password(password: str):
    return 'fakehashed' + password


class User(BaseModel):
    username: str
    email: Optional[str] = None
    full_name: Optional[str] = None
    disabled: Optional[bool] = None


class UserInDB(User):
    hashed_password: str


def get_user(db, username: str):
    if username in db:
        user_dict = db[username]
        return UserInDB(**user_dict)


def fake_decode_token(token: str):
    user = get_user(fake_users_db, token)
    return user


def get_current_user(token: str = Depends(oauth2)):
    user = fake_decode_token(token)
    if not user:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
                            detail='Invalid authentication credentials',
                            headers={'WWW-Authenticate': 'Bearer'}  # OAuth2的规范，如果认证失败，请求头中返回"WWW-Authenticate"
                            )


async def get_current_active_user(current_user: User = Depends(get_current_user)):
    if current_user.disabled:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
                            detail='Inactive user')
    return current_user


@app06.post('/token')
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user_dict = fake_users_db.get(form_data.username)
    if not user_dict:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
                            detail='Incorrect username or password!'
                            )
    user = UserInDB(**user_dict)
    hashed_password = fake_hash_password(form_data.password)
    if not hashed_password == user.hashed_password:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
                            detail='Incorrect username or password!'
                            )
    return {'access_token': user.username, 'token_type': 'bearer'}


@app06.get('/users/me')
async def read_user_me(current_user: User = Depends(get_current_active_user)):
    return current_user
